package com.zby.simulationHibernate.util.factory;

import com.zby.simulationHibernate.constant.StandardBasicTypes;
import com.zby.simulationHibernate.query.SqlQuery;
import com.zby.simulationHibernate.util.DateUtil;
import com.zby.simulationHibernate.util.common.CommonUtil;
import com.zby.simulationHibernate.util.common.StringUtil;
import com.zby.simulationHibernate.util.exception.GenericException;
import com.zby.simulationHibernate.util.reflect.ClassUtil;
import com.zby.simulationHibernate.util.reflect.PropertyUtil;
import com.zby.simulationHibernate.util.reflect.property.PropertyAccessor;
import org.apache.commons.lang3.StringUtils;

import java.lang.reflect.Field;
import java.sql.*;
import java.util.Date;

/**
 * Created By zby on 21:20 2019/1/23
 * 创建与数据库的会话
 */

public class Session<T> {

    /**
     * 与数据库的连接对象
     */
    private Connection connection;

    /**
     * 初始化PropertyAccessor对象
     *
     * @param connection
     */
    private PropertyAccessor<T> propertyAccessor;


    public Session(Connection connection) {
        this.connection = connection;
        propertyAccessor = new PropertyAccessor();
    }

    /**
     * Created By zby on 23:04 2019/1/23
     * 创建sql查询语句
     */
    public SqlQuery createSqlQuery(String sql) {
        if (CommonUtil.isNull(sql)) {
            throw new GenericException("sql不能为空");
        }
        return new SqlQuery(connection, sql);
    }

    /**
     * Created By zby on 15:41 2019/1/29
     * 合并，首先判断id是否存在，若id存在则更新，若id不存在，则保存数据
     */
    public T merge(T t) {
        if (CommonUtil.isNull(t))
            throw new IllegalArgumentException("参数为空");
        Class<T> clazz = (Class<T>) t.getClass();
        Field[] fields = clazz.getDeclaredFields();
        boolean isContainsId = CommonUtil.isNotNull(PropertyUtil.containId(fields)) ? true : false;
        long id = PropertyUtil.getIdValue(fields, t, propertyAccessor);
        if (isContainsId) {
            return id > 0L ? update(t) : save(t);
        }
        return save(t);
    }

    /**
     * Created By zby on 16:36 2019/1/29
     * 通过id获取对象
     */
    public T load(Class<T> clazz, Long id) {
        if (CommonUtil.isNull(clazz))
            throw new IllegalArgumentException("参数为空");
        String className = ClassUtil.getClassNameByClass(clazz);
        String sql = " select * from " + className + " where id= ? ";
        SqlQuery query = createSqlQuery(sql)
                .setParamter(0, id)
                .addEntity(clazz);
        return (T) query.uniqueResult();
    }

    /**
     * Created By zby on 17:37 2019/1/29
     * 保存数据
     */
    public T save(T t) {
        if (CommonUtil.isNull(t))
            throw new RuntimeException("不能保存空对象");
        PreparedStatement statement = null;
        ResultSet resultSet = null;
        StringBuilder columnJoint = new StringBuilder();
        StringBuilder columnValue = new StringBuilder();
        try {
            Field[] fields = t.getClass().getDeclaredFields();
            String sql = " insert into " + ClassUtil.getClassNameByGenericity(t) + "(";
            for (int i = 0; i < fields.length; i++) {
                String propertyName = fields[i].getName();
                Object propertyValue = propertyAccessor.getPropertyValue(t, propertyName);
                if (CommonUtil.isNotNull(propertyValue)) {
                    String columnName = PropertyUtil.propertyNameTransformColumnName(propertyName, true);
                    if (StandardBasicTypes.BOOLEAN.equalsIgnoreCase(fields[i].getGenericType().toString())) {
                        columnJoint.append("is_" + columnName + ",");
                        columnValue.append(propertyValue + ",");
                    } else if (StandardBasicTypes.LONG.equalsIgnoreCase(fields[i].getGenericType().toString())
                            || StandardBasicTypes.FLOAT.equalsIgnoreCase(fields[i].getGenericType().toString())
                            || StandardBasicTypes.DOUBLE.equalsIgnoreCase(fields[i].getGenericType().toString())
                            || StandardBasicTypes.INTEGER.equalsIgnoreCase(fields[i].getGenericType().toString())) {
                        columnJoint.append(columnName + ",");
                        columnValue.append(propertyValue + ",");
                    } else if (StandardBasicTypes.DATE.equalsIgnoreCase(fields[i].getGenericType().toString())) {
                        columnJoint.append(columnName + ",");
                        columnValue.append("'" + DateUtil.SIMPLE_DATE_FORMAT.format((Date) propertyValue) + "',");
                    } else {
                        columnJoint.append(columnName + ",");
                        columnValue.append("'" + propertyValue + "',");
                    }
                }
            }
            columnJoint = StringUtil.replace(columnJoint, ",");
            columnValue = StringUtil.replace(columnValue, ",");
            sql += columnJoint + ") VALUES(" + columnValue + ")";
            System.out.println(sql);
            statement = connection.prepareStatement(sql, Statement.RETURN_GENERATED_KEYS);
            statement.executeUpdate();
            resultSet = statement.getGeneratedKeys();
            while (resultSet.next()) {
                return load((Class<T>) t.getClass(), resultSet.getLong(1));
            }
            return t;
        } catch (SQLException e) {
            System.out.println("保存数据出错,实体对象为=" + t);
            e.printStackTrace();
        } finally {
            SessionClose.closeConnStateResSet(connection, statement, resultSet);
        }
        return null;
    }

    /**
     * Created By zby on 13:49 2019/1/30
     * 更新数据
     */
    public T update(T t) {
        if (CommonUtil.isNull(t))
            throw new RuntimeException("不能保存空对象");
        PreparedStatement statement = null;
        try {
            Field[] fields = t.getClass().getDeclaredFields();
            StringBuilder sqlBuilder = new StringBuilder(" UPDATE " + ClassUtil.getClassNameByGenericity(t) + " SET ");
            String propertyId = PropertyUtil.containId(fields);
            long id = 0;
            if (CommonUtil.isNotNull(propertyId)) {
                for (int i = 0; i < fields.length; i++) {
                    String propertyName = fields[i].getName();
                    Object propertyValue = propertyAccessor.getPropertyValue(t, propertyName);
                    id = PropertyUtil.getIdValue(fields, t, propertyAccessor);
                    if (CommonUtil.isNotNull(propertyValue)) {
                        String columnName = PropertyUtil.propertyNameTransformColumnName(propertyName, true);
                        if (StandardBasicTypes.BOOLEAN.equalsIgnoreCase(fields[i].getGenericType().toString())) {
                            columnName = "is_" + columnName;
                            sqlBuilder.append(columnName + "=" + propertyValue + ",");
                        } else if (StandardBasicTypes.LONG.equalsIgnoreCase(fields[i].getGenericType().toString())
                                || StandardBasicTypes.FLOAT.equalsIgnoreCase(fields[i].getGenericType().toString())
                                || StandardBasicTypes.DOUBLE.equalsIgnoreCase(fields[i].getGenericType().toString())
                                || StandardBasicTypes.INTEGER.equalsIgnoreCase(fields[i].getGenericType().toString())) {
                            sqlBuilder.append(columnName + "=" + propertyValue + ",");
                        } else if (StandardBasicTypes.DATE.equalsIgnoreCase(fields[i].getGenericType().toString())) {
                            String strValue = "'" + DateUtil.SIMPLE_DATE_FORMAT.format((Date) propertyValue) + "'";
                            sqlBuilder.append(columnName + "=" + strValue + ",");
                        } else {
                            sqlBuilder.append(columnName + "= '" + propertyValue + "',");
                        }
                    }
                }
            }
            sqlBuilder = StringUtil.replace(sqlBuilder, ",");
            sqlBuilder.append("where id = " + id);
            statement = connection.prepareStatement(sqlBuilder.toString());
            statement.executeUpdate();
            return load((Class<T>) t.getClass(), id);
        } catch (SQLException e) {
            System.out.println("保存数据出错,实体对象为=" + t);
            e.printStackTrace();
        } finally {
            SessionClose.closeConnAndStatement(connection, statement);
        }
        return null;
    }

    /**
     * Created By zby on 16:04 2019/1/30
     * 删除操作
     */
    public void delete(T t) {
        PreparedStatement statement = null;
        if (CommonUtil.isNull(t))
            throw new IllegalArgumentException("参数为空");
        Class<T> clazz = (Class<T>) t.getClass();
        Field[] fields = clazz.getDeclaredFields();
        String idName = PropertyUtil.containId(fields);
        if (CommonUtil.isNull(idName))
            throw new RuntimeException("删除失败");
        Long idValue = PropertyUtil.getIdValue(fields, t, propertyAccessor);
        if (idValue <= 0)
            throw new IllegalArgumentException("类" + clazz + "实例化对象的下标越界【" + idValue + "】");
        String sql = "delete from " + ClassUtil.getClassNameByGenericity(t) + " where id= ?";
        try {
            statement = connection.prepareStatement(sql);
            statement.setLong(1, idValue);
            statement.executeUpdate();
            System.out.println("删除成功");
        } catch (SQLException e) {
            e.printStackTrace();
        } finally {
            SessionClose.closeConnAndStatement(connection, statement);
        }
    }
}
